#include "pch.h"
#include "MeshLoader.h"
#include <fstream>
#include <string>
#include <memory>
#include <stdio.h>

using namespace Platform;

using namespace DXBase;
using namespace DXBase::D3D;
using namespace DXBase::Samples;

using namespace Windows::Foundation;

using namespace concurrency;

template <class T>
void CopyData(MemoryBlock^ vec, T* data, unsigned int num)
{
	auto n = num * sizeof(T);
	vec->ByteSize = n;
	memcpy((void*)vec->Data, data, n);
}


Shape^ MeshLoader::CreateCube16()
{
	basicvertex cubeVertices[] =
	{
		basicvertex(vector3(-0.5f, 0.5f, -0.5f), vector3(0.0f, 1.0f, 0.0f), vector2(0.0f, 0.0f)), // +Y (top face)
		basicvertex(vector3( 0.5f, 0.5f, -0.5f), vector3(0.0f, 1.0f, 0.0f), vector2(1.0f, 0.0f)),
		basicvertex(vector3( 0.5f, 0.5f,  0.5f), vector3(0.0f, 1.0f, 0.0f), vector2(1.0f, 1.0f)),
		basicvertex(vector3(-0.5f, 0.5f,  0.5f), vector3(0.0f, 1.0f, 0.0f), vector2(0.0f, 1.0f)),

		basicvertex(vector3(-0.5f, -0.5f,  0.5f), vector3(0.0f, -1.0f, 0.0f), vector2(0.0f, 0.0f)), // -Y (bottom face)
		basicvertex(vector3( 0.5f, -0.5f,  0.5f), vector3(0.0f, -1.0f, 0.0f), vector2(1.0f, 0.0f)),
		basicvertex(vector3 (0.5f, -0.5f, -0.5f), vector3(0.0f, -1.0f, 0.0f), vector2(1.0f, 1.0f)),
		basicvertex(vector3(-0.5f, -0.5f, -0.5f), vector3(0.0f, -1.0f, 0.0f), vector2(0.0f, 1.0f)),

		basicvertex(vector3(0.5f,  0.5f,  0.5f), vector3(1.0f, 0.0f, 0.0f), vector2(0.0f, 0.0f)), // +X (right face)
		basicvertex(vector3(0.5f,  0.5f, -0.5f), vector3(1.0f, 0.0f, 0.0f), vector2(1.0f, 0.0f)),
		basicvertex(vector3(0.5f, -0.5f, -0.5f), vector3(1.0f, 0.0f, 0.0f), vector2(1.0f, 1.0f)),
		basicvertex(vector3(0.5f, -0.5f,  0.5f), vector3(1.0f, 0.0f, 0.0f), vector2(0.0f, 1.0f)),

		basicvertex(vector3(-0.5f,  0.5f, -0.5f), vector3(-1.0f, 0.0f, 0.0f), vector2(0.0f, 0.0f)), // -X (left face)
		basicvertex(vector3(-0.5f,  0.5f,  0.5f), vector3(-1.0f, 0.0f, 0.0f), vector2(1.0f, 0.0f)),
		basicvertex(vector3(-0.5f, -0.5f,  0.5f), vector3(-1.0f, 0.0f, 0.0f), vector2(1.0f, 1.0f)),
		basicvertex(vector3(-0.5f, -0.5f, -0.5f), vector3(-1.0f, 0.0f, 0.0f), vector2(0.0f, 1.0f)),

		basicvertex(vector3(-0.5f,  0.5f, 0.5f), vector3(0.0f, 0.0f, 1.0f), vector2(0.0f, 0.0f)), // +Z (front face)
		basicvertex(vector3( 0.5f,  0.5f, 0.5f), vector3(0.0f, 0.0f, 1.0f), vector2(1.0f, 0.0f)),
		basicvertex(vector3( 0.5f, -0.5f, 0.5f), vector3(0.0f, 0.0f, 1.0f), vector2(1.0f, 1.0f)),
		basicvertex(vector3(-0.5f, -0.5f, 0.5f), vector3(0.0f, 0.0f, 1.0f), vector2(0.0f, 1.0f)),

		basicvertex(vector3( 0.5f,  0.5f, -0.5f), vector3(0.0f, 0.0f, -1.0f), vector2(0.0f, 0.0f)), // -Z (back face)
		basicvertex(vector3(-0.5f,  0.5f, -0.5f), vector3(0.0f, 0.0f, -1.0f), vector2(1.0f, 0.0f)),
		basicvertex(vector3(-0.5f, -0.5f, -0.5f), vector3(0.0f, 0.0f, -1.0f), vector2(1.0f, 1.0f)),
		basicvertex(vector3( 0.5f, -0.5f, -0.5f), vector3(0.0f, 0.0f, -1.0f), vector2(0.0f, 1.0f)),
	};
	unsigned short cubeIndices[] =
	{
		0, 1, 2,
		0, 2, 3,

		4, 5, 6,
		4, 6, 7,

		8, 9, 10,
		8, 10, 11,

		12, 13, 14,
		12, 14, 15,

		16, 17, 18,
		16, 18, 19,

		20, 21, 22,
		20, 22, 23
	};

	auto result = ref new Shape();
	result->Topology = Topology::Trianglelist;
	result->LeftHanded = false;
	result->IndexFormat = Format::R16_uint;
	result->AddVertexBuffer(sizeof(basicvertex));
	CopyData<basicvertex>(result->Vertices->GetAt(0), cubeVertices, ARRAYSIZE(cubeVertices));
	CopyData<unsigned short>(result->Indices, cubeIndices, ARRAYSIZE(cubeIndices));
	return result;
}


Shape^ MeshLoader::CreateBox16(float3 r)
{
	//
	// Create the vertices.
	//

	basicvertex v[24];

	float w2 = 0.5f*r.x;
	float h2 = 0.5f*r.y;
	float d2 = 0.5f*r.z;
    
	// Fill in the front face vertex data.
	v[0] = basicvertex(-w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f);
	v[1] = basicvertex(-w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f);
	v[2] = basicvertex(+w2, +h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f);
	v[3] = basicvertex(+w2, -h2, -d2, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f);
														 
	// Fill in the back face vertex data.				 
	v[4] = basicvertex(-w2, -h2, +d2, 0.0f, 0.0f, 1.0f,  1.0f, 1.0f);
	v[5] = basicvertex(+w2, -h2, +d2, 0.0f, 0.0f, 1.0f,  0.0f, 1.0f);
	v[6] = basicvertex(+w2, +h2, +d2, 0.0f, 0.0f, 1.0f,  0.0f, 0.0f);
	v[7] = basicvertex(-w2, +h2, +d2, 0.0f, 0.0f, 1.0f,  1.0f, 0.0f);
														 
	// Fill in the top face vertex data.				 
	v[8]  = basicvertex(-w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f);
	v[9]  = basicvertex(-w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
	v[10] = basicvertex(+w2, +h2, +d2, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
	v[11] = basicvertex(+w2, +h2, -d2, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);

	// Fill in the bottom face vertex data.
	v[12] = basicvertex(-w2, -h2, -d2, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f);
	v[13] = basicvertex(+w2, -h2, -d2, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f);
	v[14] = basicvertex(+w2, -h2, +d2, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f);
	v[15] = basicvertex(-w2, -h2, +d2, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f);

	// Fill in the left face vertex data.
	v[16] = basicvertex(-w2, -h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
	v[17] = basicvertex(-w2, +h2, +d2, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
	v[18] = basicvertex(-w2, +h2, -d2, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
	v[19] = basicvertex(-w2, -h2, -d2, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f);

	// Fill in the right face vertex data.
	v[20] = basicvertex(+w2, -h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
	v[21] = basicvertex(+w2, +h2, -d2, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f);
	v[22] = basicvertex(+w2, +h2, +d2, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f);
	v[23] = basicvertex(+w2, -h2, +d2, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f);

	//
	// Create the indices.
	//

	UINT16 i[36];

	// Fill in the front face index data
	i[0] = 0; i[1] = 1; i[2] = 2;
	i[3] = 0; i[4] = 2; i[5] = 3;

	// Fill in the back face index data
	i[6] = 4; i[7]  = 5; i[8]  = 6;
	i[9] = 4; i[10] = 6; i[11] = 7;

	// Fill in the top face index data
	i[12] = 8; i[13] =  9; i[14] = 10;
	i[15] = 8; i[16] = 10; i[17] = 11;

	// Fill in the bottom face index data
	i[18] = 12; i[19] = 13; i[20] = 14;
	i[21] = 12; i[22] = 14; i[23] = 15;

	// Fill in the left face index data
	i[24] = 16; i[25] = 17; i[26] = 18;
	i[27] = 16; i[28] = 18; i[29] = 19;

	// Fill in the right face index data
	i[30] = 20; i[31] = 21; i[32] = 22;
	i[33] = 20; i[34] = 22; i[35] = 23;

	
	// fix face
	for(UINT index = 0, N = ARRAYSIZE(i); index < N; index+=3)
	{
		auto tmp = i[index+1];
		i[index+1] = i[index+2];
		i[index+2] = tmp;
	}

	auto result = ref new Shape();
	result->Topology = Topology::Trianglelist;
	result->LeftHanded = false;
	result->IndexFormat = Format::R16_uint;
	result->AddVertexBuffer(sizeof(basicvertex));
	CopyData<basicvertex>(result->Vertices->GetAt(0), v, ARRAYSIZE(v));
	CopyData<unsigned short>(result->Indices, i, ARRAYSIZE(i));
	return result;
}



Shape^ MeshLoader::CreateSphereMesh16(float radius, UINT numticks)
{
	auto mesh = ref new Shape();
	mesh->Topology = Topology::Trianglelist;
	mesh->LeftHanded = false;
	mesh->IndexFormat = Format::R16_uint;
	mesh->AddVertexBuffer(sizeof(basicvertex));

	// Poles: note that there will be texture coordinate distortion as there is
	// not a unique point on the texture map to assign to the pole when mapping
	// a rectangular texture onto a sphere.
	basicvertex topVertex = basicvertex(0.0f, +radius, 0.0f, 0.0f, +1.0f, 0.0f, 0.0f, 0.0f);
	basicvertex bottomVertex = basicvertex(0.0f, -radius, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f);

	TPointer<basicvertex> vdata(mesh->Vertices->GetAt(0));
	vdata << ( topVertex );

	if(numticks < 6)
		throw ref new InvalidArgumentException();

	UINT sliceCount = 2*numticks;
	UINT stackCount = numticks;

	float step   = PI_F/numticks;

	// Compute vertices for each stack ring (do not count the poles as rings).
	for(UINT i = 1; i <= stackCount-1; ++i)
	{
		float phi = i*step;

		// Vertices of ring.
		for(UINT j = 0; j <= sliceCount; ++j)
		{
			float theta = j*step;

			basicvertex v;
			v.color.r = v.color.g = v.color.b = v.color.a = 255;

			// spherical to cartesian
			float3 p = vector3(-sinf(phi)*cosf(theta), cosf(phi), sinf(phi)*sinf(theta));
			v.pos = p * radius;
			v.norm = p;

			// Partial derivative of P with respect to theta
			//v.TangentU.x = -radius*sinf(phi)*sinf(theta);
			//v.TangentU.y = 0.0f;
			//v.TangentU.z = +radius*sinf(phi)*cosf(theta);

			v.tex.x = theta / PI_F / 2;
			v.tex.y = phi / PI_F;

			vdata << ( v );
		}
	}

	vdata << ( bottomVertex );

	//
	// Compute indices for top stack.  The top stack was written first to the vertex buffer
	// and connects the top pole to the first ring.
	//

	TPointer<UINT16> idata(mesh->Indices);
	for(UINT i = 1; i <= sliceCount; ++i)
	{
		idata << (0);
		idata << (i+1);
		idata << (i);
	}
	
	//
	// Compute indices for inner stacks (not connected to poles).
	//

	// Offset the indices to the index of the first vertex in the first ring.
	// This is just skipping the top pole vertex.
	UINT baseIndex = 1;
	UINT ringVertexCount = sliceCount+1;
	for(UINT i = 0; i < stackCount-2; ++i)
	{
		for(UINT j = 0; j < sliceCount; ++j)
		{
			idata << (baseIndex + i*ringVertexCount + j);
			idata << (baseIndex + i*ringVertexCount + j+1);
			idata << (baseIndex + (i+1)*ringVertexCount + j);
							
			idata << (baseIndex + (i+1)*ringVertexCount + j);
			idata << (baseIndex + i*ringVertexCount + j+1);
			idata << (baseIndex + (i+1)*ringVertexCount + j+1);
		}
	}

	//
	// Compute indices for bottom stack.  The bottom stack was written last to the vertex buffer
	// and connects the bottom pole to the bottom ring.
	//

	// South pole vertex was added last.
	UINT southPoleIndex =  vdata.Size - 1; // (UINT)meshData->vertices->data.size()-1;

	// Offset the indices to the index of the first vertex in the last ring.
	baseIndex = southPoleIndex - ringVertexCount;
	
	for(UINT i = 0; i < sliceCount; ++i)
	{
		idata << (southPoleIndex);
		idata << (baseIndex+i);
		idata << (baseIndex+i+1);
	}

	return mesh;
}
Shape^ MeshLoader::CreateReferenceAxis16()
{
	basicvertex axisVertices[] =
	{
		basicvertex(vector3( 0.500f, 0.000f, 0.000f), vector3( 0.125f, 0.500f, 0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3( 0.125f, 0.500f, 0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3( 0.125f, 0.500f, 0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.500f, 0.000f, 0.000f), vector3( 0.125f,-0.500f, 0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3( 0.125f,-0.500f, 0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3( 0.125f,-0.500f, 0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.500f, 0.000f, 0.000f), vector3( 0.125f,-0.500f,-0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3( 0.125f,-0.500f,-0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3( 0.125f,-0.500f,-0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.500f, 0.000f, 0.000f), vector3( 0.125f, 0.500f,-0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3( 0.125f, 0.500f,-0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3( 0.125f, 0.500f,-0.500f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3(-0.125f, 0.000f, 0.000f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3(-0.125f, 0.000f, 0.000f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3(-0.125f, 0.000f, 0.000f), vector2(0.250f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3(-0.125f, 0.000f, 0.000f), vector2(0.250f, 0.250f)),
		basicvertex(vector3(-0.500f, 0.000f, 0.000f), vector3(-0.125f, 0.500f, 0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3(-0.125f, 0.500f, 0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3(-0.125f, 0.500f, 0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3(-0.500f, 0.000f, 0.000f), vector3(-0.125f, 0.500f,-0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3(-0.125f, 0.500f,-0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3(-0.125f, 0.500f,-0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3(-0.500f, 0.000f, 0.000f), vector3(-0.125f,-0.500f,-0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3(-0.125f,-0.500f,-0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3(-0.125f,-0.500f,-0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3(-0.500f, 0.000f, 0.000f), vector3(-0.125f,-0.500f, 0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3(-0.125f,-0.500f, 0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3(-0.125f,-0.500f, 0.500f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3( 0.125f, 0.000f, 0.000f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3( 0.125f, 0.000f, 0.000f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3( 0.125f, 0.000f, 0.000f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3( 0.125f, 0.000f, 0.000f), vector2(0.250f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.500f, 0.000f), vector3( 0.500f, 0.125f, 0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3( 0.500f, 0.125f, 0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f, 0.125f, 0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.500f, 0.000f), vector3( 0.500f, 0.125f,-0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f, 0.125f,-0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3( 0.500f, 0.125f,-0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.500f, 0.000f), vector3(-0.500f, 0.125f,-0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3(-0.500f, 0.125f,-0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f, 0.125f,-0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.500f, 0.000f), vector3(-0.500f, 0.125f, 0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f, 0.125f, 0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3(-0.500f, 0.125f, 0.500f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.000f,-0.125f, 0.000f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3( 0.000f,-0.125f, 0.000f), vector2(0.500f, 0.250f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3( 0.000f,-0.125f, 0.000f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3( 0.000f,-0.125f, 0.000f), vector2(0.500f, 0.250f)),
		basicvertex(vector3( 0.000f,-0.500f, 0.000f), vector3( 0.500f,-0.125f, 0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f,-0.125f, 0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3( 0.500f,-0.125f, 0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.500f, 0.000f), vector3(-0.500f,-0.125f, 0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3(-0.500f,-0.125f, 0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f,-0.125f, 0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.500f, 0.000f), vector3(-0.500f,-0.125f,-0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f,-0.125f,-0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3(-0.500f,-0.125f,-0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.500f, 0.000f), vector3( 0.500f,-0.125f,-0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3( 0.500f,-0.125f,-0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f,-0.125f,-0.500f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.125f), vector3( 0.000f, 0.125f, 0.000f), vector2(0.500f, 0.500f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3( 0.000f, 0.125f, 0.000f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.125f), vector3( 0.000f, 0.125f, 0.000f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.000f, 0.125f, 0.000f), vector2(0.500f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.500f), vector3( 0.500f, 0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f, 0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3( 0.500f, 0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.500f), vector3(-0.500f, 0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3(-0.500f, 0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f, 0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.500f), vector3(-0.500f,-0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f,-0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3(-0.500f,-0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f, 0.500f), vector3( 0.500f,-0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3( 0.500f,-0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f,-0.500f, 0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.000f, 0.000f,-0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3( 0.000f, 0.000f,-0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3( 0.000f, 0.000f,-0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3( 0.000f, 0.000f,-0.125f), vector2(0.750f, 0.250f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.500f), vector3( 0.500f, 0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3( 0.500f, 0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f, 0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.500f), vector3( 0.500f,-0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.500f,-0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3( 0.500f,-0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.500f), vector3(-0.500f,-0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3(-0.500f,-0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f,-0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.000f,-0.500f), vector3(-0.500f, 0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3(-0.500f, 0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3(-0.500f, 0.500f,-0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f, 0.125f, 0.000f), vector3( 0.000f, 0.000f, 0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3(-0.125f, 0.000f, 0.000f), vector3( 0.000f, 0.000f, 0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.000f,-0.125f, 0.000f), vector3( 0.000f, 0.000f, 0.125f), vector2(0.750f, 0.500f)),
		basicvertex(vector3( 0.125f, 0.000f, 0.000f), vector3( 0.000f, 0.000f, 0.125f), vector2(0.750f, 0.500f)),
	};

	unsigned short axisIndices[] =
	{
		0,  2,  1,
		3,  5,  4,
		6,  8,  7,
		9, 11, 10,
		12, 14, 13,
		12, 15, 14,
		16, 18, 17,
		19, 21, 20,
		22, 24, 23,
		25, 27, 26,
		28, 30, 29,
		28, 31, 30,
		32, 34, 33,
		35, 37, 36,
		38, 40, 39,
		41, 43, 42,
		44, 46, 45,
		44, 47, 46,
		48, 50, 49,
		51, 53, 52,
		54, 56, 55,
		57, 59, 58,
		60, 62, 61,
		60, 63, 62,
		64, 66, 65,
		67, 69, 68,
		70, 72, 71,
		73, 75, 74,
		76, 78, 77,
		76, 79, 78,
		80, 82, 81,
		83, 85, 84,
		86, 88, 87,
		89, 91, 90,
		92, 94, 93,
		92, 95, 94,
	};

	auto result = ref new Shape();
	result->Topology = Topology::Trianglelist;
	result->LeftHanded = false;
	result->IndexFormat = Format::R16_uint;
	result->AddVertexBuffer(sizeof(basicvertex));
	CopyData<basicvertex>(result->Vertices->GetAt(0), axisVertices, ARRAYSIZE(axisVertices));
	CopyData<unsigned short>(result->Indices, axisIndices, ARRAYSIZE(axisIndices));
	return result;
}

Shape^ MeshLoader::CreateGrid32(float width, float depth, UINT m, UINT n)
{
	UINT vertexCount = m*n;
	UINT faceCount   = (m-1)*(n-1)*2;

	//
	// Create the vertices.
	//

	float halfWidth = 0.5f*width;
	float halfDepth = 0.5f*depth;

	float dx = width / (n-1);
	float dz = depth / (m-1);

	float du = 1.0f / (n-1);
	float dv = 1.0f / (m-1);

	auto result = ref new Shape();
	result->Topology = Topology::Trianglelist;
	result->LeftHanded = true;
	result->IndexFormat = Format::R32_uint;
	result->AddVertexBuffer(sizeof(basicvertex));

	TPointer<basicvertex> vdata(result->Vertices->GetAt(0));
	vdata.SetSizes(vertexCount);
	for(UINT i = 0; i < m; ++i)
	{
		float z = halfDepth - i*dz;
		for(UINT j = 0; j < n; ++j)
		{
			float x = -halfWidth + j*dx;

			vdata[i*n+j].pos = vector3(x, 0.0f, z);
			vdata[i*n+j].norm   = vector3(0.0f, 1.0f, 0.0f);
			//vdata->data[i*n+j].TangentU = vector3(1.0f, 0.0f, 0.0f);

			// Stretch texture over grid.
			vdata[i*n+j].tex.x = j*du;
			vdata[i*n+j].tex.y = i*dv;
		}
	}
 
    //
	// Create the indices.
	//

	TPointer<UINT32> idata(result->Indices);
	idata.SetSizes(faceCount*3);

	// Iterate over each quad and compute indices.
	UINT k = 0;
	for(UINT i = 0; i < m-1; ++i)
	{
		for(UINT j = 0; j < n-1; ++j)
		{
			idata[k]   = i*n+j;
			idata[k+1] = i*n+j+1;
			idata[k+2] = (i+1)*n+j;

			idata[k+3] = (i+1)*n+j;
			idata[k+4] = i*n+j+1;
			idata[k+5] = (i+1)*n+j+1;

			k += 6; // next quad
		}
	}

	return result;
}
Shape^ MeshLoader::CreateCylinder16(float bottomRadius, float topRadius, float height, UINT sliceCount, UINT stackCount)
{
	Shape^ mesh = ref new Shape();
	mesh->Topology = Topology::Trianglelist;
	mesh->LeftHanded = true;
	mesh->IndexFormat = Format::R16_uint;
	mesh->AddVertexBuffer(sizeof(basicvertex));

	//
	// Build Stacks.
	// 

	float stackHeight = height / stackCount;

	// Amount to increment radius as we move up each stack level from bottom to top.
	float radiusStep = (topRadius - bottomRadius) / stackCount;

	UINT ringCount = stackCount+1;

	TPointer<basicvertex> vdata(mesh->Vertices->GetAt(0));
	// Compute vertices for each stack ring starting at the bottom and moving up.
	for(UINT i = 0; i < ringCount; ++i)
	{
		float y = -0.5f*height + i*stackHeight;
		float r = bottomRadius + i*radiusStep;

		// vertices of ring
		float dTheta = 2.0f * PI_F / sliceCount;
		for(UINT j = 0; j <= sliceCount; ++j)
		{
			basicvertex vertex;
			vertex.color.r = vertex.color.g = vertex.color.b = vertex.color.a = 255;

			float c = cosf(j*dTheta);
			float s = sinf(j*dTheta);

			vertex.pos = vector3(r*c, y, r*s);

			vertex.tex.x = j/(float)sliceCount;
			vertex.tex.y = 1.0f - i/(float)stackCount;

			// Cylinder can be parameterized as follows, where we introduce v
			// parameter that goes in the same direction as the v tex-coord
			// so that the bitangent goes in the same direction as the v tex-coord.
			//   Let r0 be the bottom radius and let r1 be the top radius.
			//   y(v) = h - hv for v in [0,1].
			//   r(v) = r1 + (r0-r1)v
			//
			//   x(t, v) = r(v)*cos(t)
			//   y(t, v) = h - hv
			//   z(t, v) = r(v)*sin(t)
			// 
			//  dx/dt = -r(v)*sin(t)
			//  dy/dt = 0
			//  dz/dt = +r(v)*cos(t)
			//
			//  dx/dv = (r0-r1)*cos(t)
			//  dy/dv = -h
			//  dz/dv = (r0-r1)*sin(t)

			// This is unit length.
			auto tangent = vector3(-s, 0.0f, c);

			float dr = bottomRadius-topRadius;
			auto bittangent = vector3(dr*c, -height, dr*s);
			vertex.norm = normalize(cross(tangent, bittangent));

			vdata << vertex;
		}
	}

	// Add one because we duplicate the first and last vertex per ring
	// since the texture coordinates are different.
	UINT ringVertexCount = sliceCount+1;

	TPointer<UINT16> idata(mesh->Indices);
	// Compute indices for each stack.
	for(UINT16 i = 0; i < stackCount; ++i)
	{
		for(UINT16 j = 0; j < sliceCount; ++j)
		{
			idata << (i*ringVertexCount + j);
			idata << ((i+1)*ringVertexCount + j);
			idata << ((i+1)*ringVertexCount + j+1);

			idata << (i*ringVertexCount + j);
			idata << ((i+1)*ringVertexCount + j+1);
			idata << (i*ringVertexCount + j+1);
		}
	}

	BuildCylinderTopCap16(mesh, bottomRadius, topRadius, height, sliceCount, stackCount);
	BuildCylinderBottomCap16(mesh, bottomRadius, topRadius, height, sliceCount, stackCount);

	return mesh;
}

void MeshLoader::BuildCylinderTopCap16(Shape^ mesh, float bottomRadius, float topRadius, float height, 
											UINT sliceCount, UINT stackCount)
{
	TPointer<basicvertex> vdata(mesh->Vertices->GetAt(0), false);
	TPointer<UINT16> idata(mesh->Indices, false);

	UINT baseIndex = (UINT)vdata.Size;

	float y = 0.5f*height;
	float dTheta = 2.0f*PI_F/sliceCount;

	// Duplicate cap ring vertices because the texture coordinates and normals differ.
	for(UINT i = 0; i <= sliceCount; ++i)
	{
		float x = topRadius*cosf(i*dTheta);
		float z = topRadius*sinf(i*dTheta);

		// Scale down by the height to try and make top cap texture coord area
		// proportional to base.
		float u = x/height + 0.5f;
		float v = z/height + 0.5f;

		//vertices->data.push_back( basicvertex(vector3(x, y, z), 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, vector2(u, v)) );
		vdata << ( basicvertex(vector3(x, y, z), vector3(0.0f, 1.0f, 0.0f), vector2(u, v)) );
	}

	// Cap center vertex.
	//meshData.Vertices.push_back( Vertex(0.0f, y, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f) );
	vdata << ( basicvertex(vector3(0.0f, y, 0.0f), vector3(0.0f, 1.0f, 0.0f), vector2(0.5f, 0.5f)) );

	// Index of center vertex.
	UINT centerIndex = (UINT)vdata.Size-1;

	for(UINT i = 0; i < sliceCount; ++i)
	{
		idata << (centerIndex);
		idata << (baseIndex + i+1);
		idata << (baseIndex + i);
	}
}

void MeshLoader::BuildCylinderBottomCap16(Shape^ mesh, float bottomRadius, float topRadius, float height, 
											   UINT sliceCount, UINT stackCount)
{
	TPointer<basicvertex> vdata(mesh->Vertices->GetAt(0), false);
	TPointer<UINT16> idata(mesh->Indices, false);

	// 
	// Build bottom cap.
	//

	UINT baseIndex = (UINT)vdata.Size;
	float y = -0.5f*height;

	// vertices of ring
	float dTheta = 2.0f*PI_F/sliceCount;
	for(UINT i = 0; i <= sliceCount; ++i)
	{
		float x = bottomRadius*cosf(i*dTheta);
		float z = bottomRadius*sinf(i*dTheta);

		// Scale down by the height to try and make top cap texture coord area
		// proportional to base.
		float u = x/height + 0.5f;
		float v = z/height + 0.5f;

		//vertices->data.push_back( Vertex(x, y, z, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, u, v) );
		vdata <<( basicvertex(x, y, z, 0.0f, -1.0f, 0.0f, u, v) );
	}

	// Cap center vertex.
	//meshData.Vertices.push_back( Vertex(0.0f, y, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.5f) );
	vdata << ( basicvertex(0.0f, y, 0.0f, 0.0f, -1.0f, 0.0f, 0.5f, 0.5f) );

	// Cache the index of center vertex.
	UINT centerIndex = (UINT)vdata.Size-1;

	for(UINT i = 0; i < sliceCount; ++i)
	{
		idata << (centerIndex);
		idata << (baseIndex + i);
		idata << (baseIndex + i+1);
	}
}

IAsyncOperation<Shape^>^ MeshLoader::LoadFrankLunaTextModel16(Platform::String^ filename)
{
	if (!filename)
		return nullptr;

	std::ifstream fin(filename->Data());
	bool exists = fin.good();
	fin.close();
	if (!exists)
		return nullptr;

	auto tload = create_task([filename] () -> Shape^
	{
		std::ifstream fin(filename->Data());
		if (!fin.good())
		{
			fin.close();
			return nullptr;
		}

		UINT vcount = 0;
		UINT tcount = 0;
		std::string ignore;

		fin >> ignore >> vcount;
		fin >> ignore >> tcount;
		fin >> ignore >> ignore >> ignore >> ignore;
	
		auto mesh = ref new Shape();
		mesh->Topology = Topology::Trianglelist;
		mesh->LeftHanded = true;
		mesh->IndexFormat = Format::R16_uint;
		mesh->AddVertexBuffer(sizeof(basicvertex));
		TPointer<basicvertex> vdata(mesh->Vertices->GetAt(0));
		vdata.SetSizes(vcount);
		color32 c = { 255, 255, 255, 255 };
		for(UINT i = 0; i < vcount; ++i)
		{
			fin >> vdata[i].pos.x  >> vdata[i].pos.y  >> vdata[i].pos.z;
			fin >> vdata[i].norm.x >> vdata[i].norm.y >> vdata[i].norm.z;
			vdata[i].color = c;
		}

		fin >> ignore;
		fin >> ignore;
		fin >> ignore;

		TPointer<UINT16> idata(mesh->Indices);
		idata.SetSizes(3*tcount);
		for(UINT i = 0; i < tcount; ++i)
		{
			fin >> idata[i*3+0] >> idata[i*3+1] >> idata[i*3+2];
		}

		fin.close();

		return mesh;
	});
	return create_async([tload] { return tload; });
}

void MeshLoader::Subdivide32(Shape^ mesh, uint32& np, uint32& ni)
{
	TPointer<basicvertex> vdata(mesh->Vertices->GetAt(0), false);
	TPointer<UINT32> idata(mesh->Indices, false);

	// Save a copy of the input geometry.
	TPointer<basicvertex> vcopy(vdata.ptr->Copy(), false, np);
	TPointer<UINT32> icopy(idata.ptr->Copy(), false, ni);

	vdata.Size = 0;
	idata.Size = 0;

	//       v1
	//       *
	//      / \
	//     /   \
	//  m0*-----*m1
	//   / \   / \
	//  /   \ /   \
	// *-----*-----*
	// v0    m2     v2

	UINT numTris = (UINT)icopy.Size/3;
	for(UINT i = 0; i < numTris; ++i)
	{
		auto v0 = vcopy[ icopy[i*3+0] ];
		auto v1 = vcopy[ icopy[i*3+1] ];
		auto v2 = vcopy[ icopy[i*3+2] ];

		//
		// Generate the midpoints.
		//

		basicvertex m0, m1, m2;
		m0.color.r = m0.color.g = m0.color.b = m0.color.a = 255;
		m1.color.r = m1.color.g = m1.color.b = m1.color.a = 255;
		m2.color.r = m2.color.g = m2.color.b = m2.color.a = 255;

		m0.pos = lerp(v0.pos, v1.pos, 0.5f);
		m1.pos = lerp(v1.pos, v2.pos, 0.5f);
		m2.pos = lerp(v0.pos, v2.pos, 0.5f);

		m0.tex = lerp(v0.tex, v1.tex, 0.5f);
		m1.tex = lerp(v1.tex, v2.tex, 0.5f);
		m2.tex = lerp(v0.tex, v2.tex, 0.5f);

		m0.norm = normalize(lerp(v0.norm, v1.norm, 0.5f));
		m1.norm = normalize(lerp(v1.norm, v2.norm, 0.5f));
		m2.norm = normalize(lerp(v0.norm, v2.norm, 0.5f));

		//XMStoreFloat3(&m0.TangentU, XMVector3Normalize(XMLoadFloat3(&Lerp(v0.TangentU, v1.TangentU, 0.5f))));
		//XMStoreFloat3(&m1.TangentU, XMVector3Normalize(XMLoadFloat3(&Lerp(v1.TangentU, v2.TangentU, 0.5f))));
		//XMStoreFloat3(&m2.TangentU, XMVector3Normalize(XMLoadFloat3(&Lerp(v0.TangentU, v2.TangentU, 0.5f))));

		//
		// Add new geometry.
		//

		vdata << (v0); // 0
		vdata << (v1); // 1
		vdata << (v2); // 2
		vdata << (m0); // 3
		vdata << (m1); // 4
		vdata << (m2); // 5
 			  
		idata << (i*6+0);
		idata << (i*6+3);
		idata << (i*6+5);
			  
		idata << (i*6+3);
		idata << (i*6+4);
		idata << (i*6+5);
			  
		idata << (i*6+5);
		idata << (i*6+4);
		idata << (i*6+2);
			  
		idata << (i*6+3);
		idata << (i*6+1);
		idata << (i*6+4);
	}

	np = vdata.Size;
	ni = idata.Size;
}


Shape^ MeshLoader::CreateGeosphere32(float radius, UINT numSubdivisions)
{
	Shape^ mesh = ref new Shape();
	mesh->Topology = Topology::Trianglelist;
	mesh->LeftHanded = false;
	mesh->IndexFormat = Format::R32_uint;
	mesh->AddVertexBuffer(sizeof(basicvertex));

	TPointer<basicvertex> vdata(mesh->Vertices->GetAt(0));
	TPointer<UINT32> idata(mesh->Indices);

	// Put a cap on the number of subdivisions.
	numSubdivisions = min(numSubdivisions, 5u);

	// Approximate a sphere by tessellating an icosahedron.

	const float X = 0.525731f; 
	const float Z = 0.850651f;

	float3 pos[12] = 
	{
		vector3(-X, 0.0f, Z),  vector3(X, 0.0f, Z),  
		vector3(-X, 0.0f, -Z), vector3(X, 0.0f, -Z),    
		vector3(0.0f, Z, X),   vector3(0.0f, Z, -X), 
		vector3(0.0f, -Z, X),  vector3(0.0f, -Z, -X),    
		vector3(Z, X, 0.0f),   vector3(-Z, X, 0.0f), 
		vector3(Z, -X, 0.0f),  vector3(-Z, -X, 0.0f)
	};

	DWORD k[60] = 
	{
		1,4,0,  4,9,0,  4,5,9,  8,5,4,  1,8,4,    
		1,10,8, 10,3,8, 8,3,5,  3,2,5,  3,7,2,    
		3,10,7, 10,6,7, 6,11,7, 6,0,11, 6,1,0, 
		10,1,6, 11,0,9, 2,11,9, 5,2,9,  11,2,7 
	};

	vdata.Size = 12;
	idata.Size = 60;

	color32 c = { 255, 255, 255, 255 };
	for(UINT i = 0; i < 12; ++i)
	{
		vdata[i].pos = pos[i];
		vdata[i].color = c;
	}

	for(UINT i = 0; i < 60; ++i)
		idata[i] = k[i];
	// fix face
	for(UINT i = 0; i < 60; i+=3)
	{
		auto ii = idata[i+1];
		idata[i+1] = idata[i+2];
		idata[i+2] = ii;
	}

	uint32 NPoint = vdata.Size;
	uint32 NInd = idata.Size;
	for(UINT i = 0; i < numSubdivisions; ++i)
		Subdivide32(mesh, NPoint, NInd);
	vdata.Size = NPoint;
	idata.Size = NInd;

	// Project vertices onto sphere and scale.
	auto PI2 = 2 * PI_F;
	for(UINT i = 0; i < vdata.Size; ++i)
	{
		float3 n = normalize(vdata[i].pos);
		vdata[i].pos = radius * n;
		vdata[i].norm = n;

		// Derive texture coordinates from spherical coordinates.
		//float theta = MathHelper::AngleFromXY(
		//	meshData.Vertices[i].Position.x, 
		//	meshData.Vertices[i].Position.z);
		float theta = atan2f(n.z, n.x);
		if (theta < 0)
			theta += PI2;
		float phi = acosf(n.y);

		vdata[i].tex.x = theta/PI2;
		vdata[i].tex.y = phi/PI_F;

		// Partial derivative of P with respect to theta
		//vdata->data[i].TangentU.x = -radius*sinf(phi)*sinf(theta);
		//vdata->data[i].TangentU.y = 0.0f;
		//vdata->data[i].TangentU.z = +radius*sinf(phi)*cosf(theta);

		//XMVECTOR T = XMLoadFloat3(&meshData.Vertices[i].TangentU);
		//XMStoreFloat3(&meshData.Vertices[i].TangentU, XMVector3Normalize(T));
	}

	// fix texture
	auto getpoint = [&vdata,&idata](UINT i) -> basicvertex
	{
		UINT i2 = idata[i];
		return vdata[i2];
	};
	auto addshift = [&getpoint,&vdata,&idata](UINT i, int shift) 
	{
		UINT j = vdata.Size;
		auto p = getpoint(i);
		p.tex.x += shift;
		vdata << (p);
		idata[i] = j;
	};
	for(INT i = (INT)idata.Size-3; i >= 0; i -= 3)
	{
		auto tx0 = getpoint(i).tex.x;
		auto tx1 = getpoint(i+1).tex.x;
		auto tx2 = getpoint(i+2).tex.x;

		if (fabs(tx0-1-tx1) < fabs(tx0-tx1) && fabs(tx0-1-tx2) < fabs(tx0-tx2))
			addshift(i, -1);
		else if (fabs(tx1-1-tx0) < fabs(tx1-tx0) && fabs(tx1-1-tx2) < fabs(tx1-tx2))
			addshift(i+1, -1);
		else if (fabs(tx2-1-tx0) < fabs(tx2-tx0) && fabs(tx2-1-tx1) < fabs(tx2-tx1))
			addshift(i+2, -1);
		else if (fabs(tx0+1-tx1) < fabs(tx0-tx1) && fabs(tx0+1-tx2) < fabs(tx0-tx2))
			addshift(i, +1);
		else if (fabs(tx1+1-tx0) < fabs(tx1-tx0) && fabs(tx1+1-tx2) < fabs(tx1-tx2))
			addshift(i+1, +1);
		else if (fabs(tx2+1-tx0) < fabs(tx2-tx0) && fabs(tx2+1-tx1) < fabs(tx2-tx1))
			addshift(i+2, +1);
	}

	return mesh;
}